"""
WebSocket Consumer for SSH Terminal
"""
import json
import paramiko
import threading
import time
import re
from channels.generic.websocket import WebsocketConsumer
from .models import Host, AuditLog
from django.utils import timezone


class SSHConsumer(WebsocketConsumer):
    """SSH终端WebSocket消费者"""
    
    # 危险命令模式列表
    DANGEROUS_COMMANDS = [
        # 文件删除类
        r'rm\s+(-[rfRF]*\s+)*/+\s*$',  # rm -rf / 或 rm -rf /*
        r'rm\s+(-[rfRF]*\s+)*/\*',     # rm -rf /*
        r'rm\s+(-[rfRF]*\s+)/boot',    # rm -rf /boot
        r'rm\s+(-[rfRF]*\s+)/etc',     # rm -rf /etc
        r'rm\s+(-[rfRF]*\s+)/usr',     # rm -rf /usr
        r'rm\s+(-[rfRF]*\s+)/var',     # rm -rf /var
        
        # 磁盘操作类
        r'dd\s+.*of=/dev/(sd[a-z]|hd[a-z]|vd[a-z])',  # dd 直接写硬盘
        r'mkfs\..*\s+/dev/',           # 格式化磁盘
        r'fdisk\s+/dev/',              # 分区操作
        
        # 系统关机类
        r'shutdown\s+(-[hHrR]|now)',   # 关机/重启
        r'halt',                        # 停机
        r'poweroff',                    # 断电
        r'reboot',                      # 重启
        r'init\s+[06]',               # 运行级别切换
        
        # 网络操作类
        r'iptables\s+(-F|-X)',        # 清空防火墙规则
        r'ifconfig\s+\w+\s+down',     # 关闭网卡
        r'ip\s+link\s+set\s+\w+\s+down',  # 关闭网卡
        
        # 权限操作类
        r'chmod\s+777\s+/',           # 根目录权限修改
        r'chmod\s+(-R\s+)?777\s+/etc',  # /etc 权限修改
        r'chown\s+.*\s+/',            # 根目录所有者修改
        
        # 用户操作类
        r'userdel\s+root',            # 删除 root 用户
        r'passwd\s+(-d\s+)?root',    # 修改 root 密码
        
        # 危险符号操作
        r':(){:\|:&};:',              # fork 炸弹
        r'>(\s+|\s*)/dev/sd[a-z]',   # 重定向到硬盘设备
    ]
    
    # 警告级别的命令模式（不是立即危险，但需要记录）
    WARNING_COMMANDS = [
        r'rm\s+-[rf]*',               # 任何 rm -rf 操作
        r'kill\s+-9',                 # 强制杀死进程
        r'pkill',                      # 批量杀进程
        r'systemctl\s+stop',          # 停止系统服务
        r'service\s+\w+\s+stop',     # 停止服务
        r'chmod\s+777',               # 777 权限
        r'iptables',                   # 防火墙操作
        r'firewalld',                  # 防火墙操作
        r'setenforce\s+0',           # 关闭 SELinux
        r'mv\s+.*\s+/dev/null',      # 移动到 /dev/null
    ]
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.command_buffer = ""  # 命令缓冲区，用于检测rz/sz
        self.rz_detected = False  # 是否检测到rz/sz命令
        self.session_commands = []  # 会话命令历史
        self.command_start_time = None  # 命令开始时间
        self.session_recording = []  # 会话录制数据（用于回放）
        self.session_start_time = None  # 会话开始时间
        self.warned_commands = set()  # 已警告过的命令（避免重复警告）
    
    def connect(self):
        """建立WebSocket连接"""
        self.host_id = self.scope['url_route']['kwargs']['host_id']
        
        # 先accept连接，否则无法发送错误消息
        self.accept()
        
        # 获取当前用户
        user = self.scope.get('user')
        
        # 检查用户是否已认证
        if not user or not user.is_authenticated:
            self.send(text_data=json.dumps({
                'type': 'error',
                'message': '未登录，无法连接SSH'
            }))
            self.close()
            return
        
        # 检查用户SSH权限（超级用户始终有权限）
        if not user.is_superuser:
            try:
                from .models import UserProfile
                profile, created = UserProfile.objects.get_or_create(user=user)
                
                # 如果是新创建的profile，默认给予SSH权限（简化使用）
                if created:
                    profile.can_use_ssh = True
                    profile.save()
                    print(f"新用户 {user.username} 已自动获得SSH权限")
                
                if not profile.can_use_ssh:
                    self.send(text_data=json.dumps({
                        'type': 'error',
                        'message': '您没有SSH连接权限，请联系管理员授权'
                    }))
                    self.close()
                    return
            except Exception as e:
                # 如果检查失败，记录日志但允许连接（避免阻止正常用户）
                print(f"SSH权限检查异常: {str(e)}, 允许用户 {user.username} 连接")
                # 继续连接
        
        try:
            # 获取主机信息
            self.host = Host.objects.get(id=self.host_id)
            
            # 检查认证信息
            if self.host.auth_type == 'password' and not self.host.password:
                self.send(text_data=json.dumps({
                    'type': 'error',
                    'message': '主机未配置SSH密码，请先编辑主机并设置密码'
                }))
                self.close()
                return
            
            if self.host.auth_type == 'key' and not self.host.ssh_key:
                self.send(text_data=json.dumps({
                    'type': 'error',
                    'message': '主机未配置SSH密钥，请先编辑主机并设置密钥'
                }))
                self.close()
                return
            
            # 创建SSH客户端
            self.ssh_client = paramiko.SSHClient()
            self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # 根据认证方式连接
            if self.host.auth_type == 'password':
                self.ssh_client.connect(
                    hostname=self.host.ip,
                    port=self.host.port,
                    username=self.host.username,
                    password=self.host.password,
                    timeout=10,
                    allow_agent=False,
                    look_for_keys=False
                )
            else:  # key authentication
                from io import StringIO
                pkey = None
                last_error = None
                
                # 尝试不同的密钥类型
                key_types = [
                    ('RSA', paramiko.RSAKey),
                    ('DSS', paramiko.DSSKey),
                    ('ECDSA', paramiko.ECDSAKey),
                    ('Ed25519', paramiko.Ed25519Key),
                ]
                
                for key_name, key_class in key_types:
                    try:
                        key_file = StringIO(self.host.ssh_key)
                        pkey = key_class.from_private_key(key_file)
                        print(f"成功加载 {key_name} 密钥")
                        break
                    except Exception as e:
                        last_error = str(e)
                        continue
                
                if pkey is None:
                    self.send(text_data=json.dumps({
                        'type': 'error',
                        'message': f'SSH密钥格式错误: {last_error}'
                    }))
                    self.close()
                    return
                
                self.ssh_client.connect(
                    hostname=self.host.ip,
                    port=self.host.port,
                    username=self.host.username,
                    pkey=pkey,
                    timeout=10,
                    allow_agent=False,
                    look_for_keys=False
                )
            
            # 创建交互式shell
            self.channel = self.ssh_client.invoke_shell(term='xterm')
            self.channel.settimeout(0.0)
            
            # 启动读取线程
            self.running = True
            self.read_thread = threading.Thread(target=self.read_from_ssh)
            self.read_thread.daemon = True
            self.read_thread.start()
            
            # 记录会话开始时间
            self.session_start_time = time.time()
            
            # 发送连接成功消息
            self.send(text_data=json.dumps({
                'type': 'connected',
                'message': f'已连接到 {self.host.name} ({self.host.ip})'
            }))
            
        except Host.DoesNotExist:
            self.send(text_data=json.dumps({
                'type': 'error',
                'message': '主机不存在'
            }))
            self.close()
        except paramiko.AuthenticationException:
            error_message = f'SSH认证失败：用户名或密码错误\n主机: {self.host.name} ({self.host.ip}:{self.host.port})\n用户名: {self.host.username}'
            
            # 记录审计日志
            AuditLog.objects.create(
                level='error',
                action='ssh_auth_failed',
                host=self.host,
                host_ip=self.host.ip,
                host_name=self.host.name,
                title='🔒 SSH终端认证失败',
                message=f'用户尝试通过Web终端连接主机 {self.host.name} ({self.host.ip}:{self.host.port}) 时认证失败，用户名: {self.host.username}',
                user=self.scope.get('user'),
                extra_data={
                    'connection_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
                    'auth_type': self.host.auth_type,
                    'username': self.host.username
                }
            )
            
            self.send(text_data=json.dumps({
                'type': 'error',
                'message': error_message
            }))
            self.close()
        except paramiko.SSHException as e:
            error_message = f'SSH连接错误: {str(e)}\n主机: {self.host.name} ({self.host.ip}:{self.host.port})'
            
            # 记录审计日志
            AuditLog.objects.create(
                level='error',
                action='ssh_connection_error',
                host=self.host,
                host_ip=self.host.ip,
                host_name=self.host.name,
                title='⚠️ SSH终端连接错误',
                message=f'用户尝试通过Web终端连接主机 {self.host.name} ({self.host.ip}:{self.host.port}) 时发生SSH错误: {str(e)}',
                user=self.scope.get('user'),
                extra_data={
                    'connection_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
                    'error': str(e)
                }
            )
            
            self.send(text_data=json.dumps({
                'type': 'error',
                'message': error_message
            }))
            self.close()
        except TimeoutError:
            error_message = f'连接超时：无法连接到主机\n主机: {self.host.name} ({self.host.ip}:{self.host.port})\n\n可能的原因：\n1. 主机已关机或SSH服务未启动\n2. 网络不通\n3. 防火墙阻止连接'
            
            # 记录审计日志
            AuditLog.objects.create(
                level='error',
                action='host_offline',
                host=self.host,
                host_ip=self.host.ip,
                host_name=self.host.name,
                title='❌ SSH终端连接超时',
                message=f'用户尝试通过Web终端连接主机 {self.host.name} ({self.host.ip}:{self.host.port}) 时连接超时，主机可能已关机或网络不通',
                user=self.scope.get('user'),
                extra_data={
                    'connection_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
                    'error': '连接超时'
                }
            )
            
            self.send(text_data=json.dumps({
                'type': 'error',
                'message': error_message
            }))
            self.close()
        except Exception as e:
            error_msg = str(e)
            # 根据错误类型提供更友好的提示
            if 'timed out' in error_msg.lower():
                message = f'连接超时：无法连接到主机\n主机: {self.host.name} ({self.host.ip}:{self.host.port})\n\n可能的原因：\n1. 主机已关机或SSH服务未启动\n2. 网络不通\n3. 防火墙阻止连接'
                log_title = '❌ SSH终端连接超时'
            elif 'connection refused' in error_msg.lower():
                message = f'连接被拒绝：SSH服务未启动或端口错误\n主机: {self.host.name} ({self.host.ip}:{self.host.port})\n\n建议：\n1. 检查SSH服务是否运行\n2. 验证SSH端口是否正确'
                log_title = '🚫 SSH终端连接被拒绝'
            elif 'no route to host' in error_msg.lower():
                message = f'网络不可达：无法连接到主机\n主机: {self.host.name} ({self.host.ip}:{self.host.port})\n\n建议：检查网络连接和IP地址是否正确'
                log_title = '🌐 SSH终端网络不可达'
            else:
                message = f'连接失败: {error_msg}\n主机: {self.host.name} ({self.host.ip}:{self.host.port})'
                log_title = '❌ SSH终端连接失败'
            
            # 记录审计日志
            AuditLog.objects.create(
                level='error',
                action='host_offline',
                host=self.host,
                host_ip=self.host.ip,
                host_name=self.host.name,
                title=log_title,
                message=f'用户尝试通过Web终端连接主机 {self.host.name} ({self.host.ip}:{self.host.port}) 失败: {error_msg}',
                user=self.scope.get('user'),
                extra_data={
                    'connection_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
                    'error': error_msg
                }
            )
            
            self.send(text_data=json.dumps({
                'type': 'error',
                'message': message
            }))
            self.close()
    
    def disconnect(self, close_code):
        """断开WebSocket连接"""
        self.running = False
        if hasattr(self, 'channel'):
            self.channel.close()
        if hasattr(self, 'ssh_client'):
            self.ssh_client.close()
    
    def receive(self, text_data):
        """接收来自WebSocket的数据"""
        try:
            data = json.loads(text_data)
            
            if data.get('type') == 'stdin':
                # 将数据写入SSH channel
                command = data.get('data', '')
                
                if hasattr(self, 'channel'):
                    # 更新命令缓冲区
                    if command == '\r':  # 回车键，命令结束
                        # 检查并记录命令
                        self._check_and_log_command(self.command_buffer.strip())
                        # 检测是否为rz或sz命令
                        cmd_lower = self.command_buffer.strip().lower()
                        if cmd_lower in ['rz', 'sz', 'rz -y', 'sz -y', 'rz -be', 'sz -be']:
                            # 检测到rz/sz命令，发送Ctrl+C中断
                            self.rz_detected = True
                            self.channel.send('\x03')  # 发送Ctrl+C
                            
                            # 发送警告消息
                            warning_msg = (
                                '\r\n\x1b[33m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\r\n'
                                '\x1b[33m⚠️  警告: 本系统不支持 rz/sz (ZModem) 命令\x1b[0m\r\n'
                                '\x1b[33m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\r\n'
                                '\r\n'
                                '\x1b[36m💡 原因说明:\x1b[0m\r\n'
                                '   rz/sz 命令依赖 ZModem 协议，该协议需要特殊的二进制\r\n'
                                '   传输支持，标准的 Web 终端无法直接处理这种协议。\r\n'
                                '\r\n'
                                '\x1b[32m✅ 替代方案:\x1b[0m\r\n'
                                '   请使用终端右上角的 \x1b[1m[📤 上传文件]\x1b[0m 按钮\r\n'
                                '   • 支持单个或多个文件上传\r\n'
                                '   • 实时显示上传进度\r\n'
                                '   • 文件自动保存到 /tmp/ 目录\r\n'
                                '   • 更加安全和可靠\r\n'
                                '\r\n'
                                '\x1b[33m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\r\n'
                            )
                            self.send(text_data=json.dumps({
                                'type': 'stdout',
                                'data': warning_msg
                            }))
                            
                            # 清空命令缓冲区
                            self.command_buffer = ""
                            return
                        
                        # 正常命令，清空缓冲区和警告记录
                        self.command_buffer = ""
                        self.warned_commands.clear()  # 清除警告记录，允许下次重新检测
                        self.channel.send(command)
                    elif command == '\x7f':  # 退格键
                        if self.command_buffer:
                            self.command_buffer = self.command_buffer[:-1]
                            # 注意：退格时不清空 warned_commands，避免删除后重新输入导致重复警告
                        self.channel.send(command)
                    elif command == '\x03':  # Ctrl+C
                        # 如果是用户主动按Ctrl+C，清空缓冲区
                        self.command_buffer = ""
                        self.rz_detected = False
                        self.warned_commands.clear()  # 清除警告记录
                        self.channel.send(command)
                    elif ord(command[0]) >= 32 and ord(command[0]) < 127:  # 可打印字符
                        self.command_buffer += command
                        self.channel.send(command)
                        # 记录输入到会话录制
                        self._record_session_data('input', command)
                        # 实时检测危险命令（输入中检测）
                        self._realtime_check_dangerous_command()
                    else:  # 其他控制字符
                        self.channel.send(command)
                        # 记录控制字符到会话录制
                        self._record_session_data('input', command)
            
            elif data.get('type') == 'resize':
                # 调整终端大小
                cols = data.get('cols', 80)
                rows = data.get('rows', 24)
                if hasattr(self, 'channel'):
                    self.channel.resize_pty(width=cols, height=rows)
                    
        except Exception as e:
            self.send(text_data=json.dumps({
                'type': 'error',
                'message': f'处理命令失败: {str(e)}'
            }))
    
    def read_from_ssh(self):
        """从SSH channel读取数据"""
        while self.running:
            try:
                if hasattr(self, 'channel') and self.channel.recv_ready():
                    data = self.channel.recv(1024)
                    if data:
                        decoded_data = data.decode('utf-8', errors='ignore')
                        # 记录输出到会话录制
                        self._record_session_data('output', decoded_data)
                        self.send(text_data=json.dumps({
                            'type': 'stdout',
                            'data': decoded_data
                        }))
                else:
                    time.sleep(0.01)
            except Exception as e:
                if self.running:
                    self.send(text_data=json.dumps({
                        'type': 'error',
                        'message': f'读取数据失败: {str(e)}'
                    }))
                break
    
    def _check_and_log_command(self, command):
        """检查命令并记录到审计日志"""
        if not command or command.strip() == '':
            return
        
        # 记录命令到会话历史
        self.session_commands.append({
            'command': command,
            'timestamp': timezone.now().isoformat(),
        })
        
        # 检查是否为危险命令
        is_dangerous = False
        is_warning = False
        matched_pattern = None
        
        # 检查危险命令
        for pattern in self.DANGEROUS_COMMANDS:
            if re.search(pattern, command, re.IGNORECASE):
                is_dangerous = True
                matched_pattern = pattern
                break
        
        # 如果不是危险命令，检查警告命令
        if not is_dangerous:
            for pattern in self.WARNING_COMMANDS:
                if re.search(pattern, command, re.IGNORECASE):
                    is_warning = True
                    matched_pattern = pattern
                    break
        
        # 记录到审计日志
        if is_dangerous or is_warning:
            user = self.scope.get('user')
            host = getattr(self, 'host', None)
            
            if is_dangerous:
                level = 'critical'
                title = '🚨 检测到高危命令'
                action_type = 'dangerous_command'
                message = (
                    f'用户在 SSH 终端执行了高危命令！\n'
                    f'主机: {host.name if host else "Unknown"} ({host.ip if host else "Unknown"})\n'
                    f'用户: {user.username if user else "Anonymous"}\n'
                    f'命令: {command}\n'
                    f'时间: {timezone.now().strftime("%Y-%m-%d %H:%M:%S")}\n\n'
                    f'⚠️ 该命令可能导致系统损坏、数据丢失或服务中断！'
                )
                
                # 发送警告到终端
                warning_msg = (
                    '\r\n\x1b[41;97m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\r\n'
                    '\x1b[41;97m  🚨  危 险 命 令 警 告  🚨  \x1b[0m\r\n'
                    '\x1b[41;97m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\r\n'
                    '\r\n'
                    f'\x1b[91m检测到高危命令: {command}\x1b[0m\r\n'
                    '\r\n'
                    '\x1b[93m⚠️  该命令可能导致:\x1b[0m\r\n'
                    '   • 系统文件被破坏\r\n'
                    '   • 重要数据丢失\r\n'
                    '   • 系统服务中断\r\n'
                    '   • 无法恢复的损害\r\n'
                    '\r\n'
                    '\x1b[96m📝 本次操作已被记录到审计日志\x1b[0m\r\n'
                    '\x1b[41;97m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\r\n'
                )
                self.send(text_data=json.dumps({
                    'type': 'stdout',
                    'data': warning_msg
                }))
                
            else:  # is_warning
                level = 'warning'
                title = '⚠️ 检测到敏感命令'
                action_type = 'sensitive_command'
                message = (
                    f'用户在 SSH 终端执行了敏感命令\n'
                    f'主机: {host.name if host else "Unknown"} ({host.ip if host else "Unknown"})\n'
                    f'用户: {user.username if user else "Anonymous"}\n'
                    f'命令: {command}\n'
                    f'时间: {timezone.now().strftime("%Y-%m-%d %H:%M:%S")}'
                )
            
            # 创建审计日志
            try:
                AuditLog.objects.create(
                    level=level,
                    action=action_type,
                    host=host,
                    host_ip=host.ip if host else None,
                    host_name=host.name if host else 'Unknown',
                    title=title,
                    message=message,
                    user=user,
                    extra_data={
                        'command': command,
                        'matched_pattern': matched_pattern,
                        'session_commands': self.session_commands[-10:],  # 最近10条命令
                        'connection_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
                        'terminal_type': 'web_ssh',
                        'is_dangerous': is_dangerous,
                        'is_executed': True,  # 标记为已执行
                        'detection_type': 'on_execute',  # 执行时检测
                        'session_recording': self.session_recording[-200:] if is_dangerous else self.session_recording[-50:],  # 危险命令保留更多上下文
                        'has_recording': len(self.session_recording) > 0,
                    }
                )
            except Exception as e:
                print(f"记录审计日志失败: {str(e)}")
    
    def _record_session_data(self, data_type, data):
        """记录会话数据用于回放"""
        if self.session_start_time is None:
            return
        
        # 计算相对时间（秒）
        elapsed_time = time.time() - self.session_start_time
        
        # 添加到录制数据
        self.session_recording.append({
            'time': round(elapsed_time, 3),  # 保留3位小数
            'type': data_type,  # 'input' or 'output'
            'data': data
        })
        
        # 限制录制数据大小（最多保留最近 5000 条记录）
        if len(self.session_recording) > 5000:
            self.session_recording = self.session_recording[-5000:]
    
    def _realtime_check_dangerous_command(self):
        """实时检测危险命令（在输入过程中）"""
        current_command = self.command_buffer.strip()
        
        # 命令太短，不检测
        if len(current_command) < 5:
            return
        
        # 检查是否已经警告过这个命令
        if current_command in self.warned_commands:
            return
        
        # 检查是否匹配危险命令模式
        is_dangerous = False
        is_warning = False
        matched_pattern = None
        
        # 检查危险命令
        for pattern in self.DANGEROUS_COMMANDS:
            if re.search(pattern, current_command, re.IGNORECASE):
                is_dangerous = True
                matched_pattern = pattern
                break
        
        # 如果不是危险命令，检查警告命令
        if not is_dangerous:
            for pattern in self.WARNING_COMMANDS:
                if re.search(pattern, current_command, re.IGNORECASE):
                    is_warning = True
                    matched_pattern = pattern
                    break
        
        # 如果检测到危险或敏感命令
        if is_dangerous or is_warning:
            # 标记为已警告，避免重复
            self.warned_commands.add(current_command)
            
            # 立即记录到审计日志
            user = self.scope.get('user')
            host = getattr(self, 'host', None)
            
            if is_dangerous:
                level = 'critical'
                title = '🚨 检测到高危命令输入'
                action_type = 'dangerous_command'
                message = (
                    f'用户在 SSH 终端输入了高危命令（未执行）！\n'
                    f'主机: {host.name if host else "Unknown"} ({host.ip if host else "Unknown"})\n'
                    f'用户: {user.username if user else "Anonymous"}\n'
                    f'命令: {current_command}\n'
                    f'时间: {timezone.now().strftime("%Y-%m-%d %H:%M:%S")}\n\n'
                    f'⚠️ 该命令可能导致系统损坏、数据丢失或服务中断！\n'
                    f'注意：命令已被输入但尚未执行。'
                )
                
                # 发送实时警告到终端
                warning_msg = (
                    '\r\n\x1b[41;97m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\r\n'
                    '\x1b[41;97m  🚨  危 险 命 令 警 告  🚨  \x1b[0m\r\n'
                    '\x1b[41;97m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\r\n'
                    '\r\n'
                    f'\x1b[91m检测到高危命令输入: {current_command}\x1b[0m\r\n'
                    '\r\n'
                    '\x1b[93m⚠️  该命令可能导致:\x1b[0m\r\n'
                    '   • 系统文件被破坏\r\n'
                    '   • 重要数据丢失\r\n'
                    '   • 系统服务中断\r\n'
                    '   • 无法恢复的损害\r\n'
                    '\r\n'
                    '\x1b[96m📝 本次输入已被记录到审计日志\x1b[0m\r\n'
                    '\x1b[93m💡 建议：如不需要执行，请按 Ctrl+C 取消\x1b[0m\r\n'
                    '\x1b[41;97m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\r\n'
                )
                self.send(text_data=json.dumps({
                    'type': 'stdout',
                    'data': warning_msg
                }))
                
            else:  # is_warning
                level = 'warning'
                title = '⚠️ 检测到敏感命令输入'
                action_type = 'sensitive_command'
                message = (
                    f'用户在 SSH 终端输入了敏感命令（未执行）\n'
                    f'主机: {host.name if host else "Unknown"} ({host.ip if host else "Unknown"})\n'
                    f'用户: {user.username if user else "Anonymous"}\n'
                    f'命令: {current_command}\n'
                    f'时间: {timezone.now().strftime("%Y-%m-%d %H:%M:%S")}\n'
                    f'注意：命令已被输入但尚未执行。'
                )
            
            # 创建审计日志
            try:
                AuditLog.objects.create(
                    level=level,
                    action=action_type,
                    host=host,
                    host_ip=host.ip if host else None,
                    host_name=host.name if host else 'Unknown',
                    title=title,
                    message=message,
                    user=user,
                    extra_data={
                        'command': current_command,
                        'matched_pattern': matched_pattern,
                        'session_commands': self.session_commands[-10:],
                        'connection_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
                        'terminal_type': 'web_ssh',
                        'is_dangerous': is_dangerous,
                        'is_executed': False,  # 标记为未执行
                        'detection_type': 'realtime_input',  # 实时输入检测
                        'session_recording': self.session_recording[-100:] if is_dangerous else self.session_recording[-30:],
                        'has_recording': len(self.session_recording) > 0,
                    }
                )
            except Exception as e:
                print(f"记录实时审计日志失败: {str(e)}")
